package mmpathgen.callgraphanalysis;

import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import soot.SootMethod;
import soot.SourceLocator;
import soot.toolkits.graph.DirectedGraph;
import soot.toolkits.graph.Orderer;
import soot.toolkits.graph.PseudoTopologicalOrderer;
import soot.util.dot.DotGraph;
import soot.util.dot.DotGraphEdge;
import soot.util.dot.DotGraphNode;

public class CallGraphToDotGraph {

	protected Map<Object, Integer> order; // SootMethod -> topo order

	@SuppressWarnings("unchecked")
	public void callGraphToDotGraph(DirectedGraph cg, String mainClass,
			String cgaType, String filtType) {

		String name = "CallGraph_" + mainClass + "_" + cgaType + "_" + filtType;
		DotGraph dot = new DotGraph(name);
		dot.setGraphLabel(name);
		dot.setGraphAttribute("compound", "true");
		dot.setGraphAttribute("rankdir", "LR");
		int id = 0;
		Map<SootMethod, Integer> idmap = new HashMap<SootMethod, Integer>();

		// construct pseudo topological order on filtered methods
		this.order = new HashMap<Object, Integer>();
		Orderer o = new PseudoTopologicalOrderer();
		Iterator orderit = (o.newList(cg, true)).iterator();
		int i = 0;
		while (orderit.hasNext()) {
			this.order.put(orderit.next(), new Integer(i));
			i++;
		}

		// draw sub-graph cluster
		Iterator it = cg.iterator();
		while (it.hasNext()) {
			SootMethod m = (SootMethod) it.next();

			DotGraph sub = dot.createSubGraph("cluster" + id);
			DotGraphNode label = sub.drawNode("head" + id);
			// DotGraphNode label = dot.drawNode("head" + id);

			idmap.put(m, new Integer(id));
			sub.setGraphLabel("");
			label.setLabel("(" + order.get(m) + ") " + m.toString());
			label.setAttribute("fontsize", "18");
			label.setShape("box");
			id++;
		}

		// connect edges
		it = cg.iterator();
		while (it.hasNext()) {
			SootMethod m = (SootMethod) it.next();
			Iterator itt = cg.getSuccsOf(m).iterator();
			while (itt.hasNext()) {
				SootMethod mm = (SootMethod) itt.next();
				DotGraphEdge edge = dot.drawEdge("head" + idmap.get(m), "head"
						+ idmap.get(mm));
				edge.setAttribute("ltail", "cluster" + idmap.get(m));
				edge.setAttribute("lhead", "cluster" + idmap.get(mm));
			}

		}

		File f = new File(SourceLocator.v().getOutputDir(), name + DotGraph.DOT_EXTENSION);
		dot.plot(f.getPath());

	}

	@SuppressWarnings("unchecked")
	public void callGraphToDotGraph(DirectedGraph cg, String mainClass,
			String cgaType, String filtType, String cfaType) {

		String name = "CallGraph_" + mainClass + "_" + cgaType + "_" + filtType;
		DotGraph dot = new DotGraph(name);
		dot.setGraphLabel(name);
		dot.setGraphAttribute("compound", "true");
		dot.setGraphAttribute("rankdir", "LR");
		int id = 0;
		Map<SootMethod, Integer> idmap = new HashMap<SootMethod, Integer>();

		// construct pseudo topological order on filtered methods
		this.order = new HashMap<Object, Integer>();
		Orderer o = new PseudoTopologicalOrderer();
		Iterator orderit = (o.newList(cg, true)).iterator();
		int i = 0;
		while (orderit.hasNext()) {
			this.order.put(orderit.next(), new Integer(i));
			i++;
		}

		// draw sub-graph cluster
		Iterator it = cg.iterator();
		while (it.hasNext()) {
			SootMethod m = (SootMethod) it.next();

			DotGraph sub = dot.createSubGraph("cluster" + id);
			DotGraphNode label = sub.drawNode("head" + id);
			// DotGraphNode label = dot.drawNode("head" + id);

			idmap.put(m, new Integer(id));
			sub.setGraphLabel("");
			label.setLabel("(" + order.get(m) + ") " + m.toString());
			label.setAttribute("fontsize", "18");
			label.setShape("box");
			id++;
		}

		// connect edges
		it = cg.iterator();
		while (it.hasNext()) {
			SootMethod m = (SootMethod) it.next();
			Iterator itt = cg.getSuccsOf(m).iterator();
			while (itt.hasNext()) {
				SootMethod mm = (SootMethod) itt.next();
				DotGraphEdge edge = dot.drawEdge("head" + idmap.get(m), "head"
						+ idmap.get(mm));
				edge.setAttribute("ltail", "cluster" + idmap.get(m));
				edge.setAttribute("lhead", "cluster" + idmap.get(mm));
			}

		}

		File f = new File(SourceLocator.v().getOutputDir(), name
				+ DotGraph.DOT_EXTENSION);
		dot.plot(f.getPath());

	}

}
